import socket
import os
import struct
import threading
import logging
import time

# 基础配置
PORT = 3000
BASE_DIR = os.path.abspath(R'E:\fantianmingDocument')
MAX_CONNECTIONS = 5  # 最大连接数
server = None
server_running = False

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# 确保基础目录存在
if not os.path.exists(BASE_DIR):
    os.makedirs(BASE_DIR)

def is_safe_path(base, path):
    # 确保路径在基础目录内
    return os.path.abspath(path).startswith(os.path.abspath(base))

def handle_client(conn, addr):
    logging.info(f"[{addr}] 新连接建立")
    try:
        while True:
            # 读取协议版本
            version = conn.recv(1)
            logging.info(f'version:{version}')
            if not version:
                break
            version = struct.unpack('B', version)[0]
            if version != 0x01:
                raise ValueError(f"[{addr}] 协议版本错误: {version}")

            # 读取文件夹名长度
            name_len = struct.unpack('>H', conn.recv(2))[0]
            folder_name = conn.recv(name_len).decode('utf-8')

            # 读取文件总数
            file_count = struct.unpack('>Q', conn.recv(8))[0]
            logging.info(f"[{addr}] 文件夹: {folder_name}, 文件总数: {file_count}")

            # 创建目标文件夹
            target_dir = os.path.join(BASE_DIR, folder_name)
            if not is_safe_path(BASE_DIR, target_dir):
                raise ValueError(f"[{addr}] 路径越界攻击尝试: {target_dir}")
            os.makedirs(target_dir, exist_ok=True)

            for _ in range(file_count):
                # 读取文件标识
                mark = conn.recv(1)
                if not mark:
                    break
                mark = struct.unpack('B', mark)[0]
                if mark != 0x02:
                    raise ValueError(f"[{addr}] 文件标识错误: {mark}")

                # 读取路径长度
                path_len = struct.unpack('>H', conn.recv(2))[0]
                file_path = conn.recv(path_len).decode('utf-8')

                # 读取文件大小
                file_size = struct.unpack('>Q', conn.recv(8))[0]
                logging.info(f"[{addr}] 开始接收文件: {file_path}, 大小: {file_size}字节")

                # 创建文件写入流
                full_path = os.path.join(target_dir, file_path)
                if not is_safe_path(BASE_DIR, full_path):
                    raise ValueError(f"[{addr}] 路径越界攻击尝试: {full_path}")
                os.makedirs(os.path.dirname(full_path), exist_ok=True)

                with open(full_path, 'wb') as f:
                    received = 0
                    while received < file_size:
                        chunk = conn.recv(min(4096, file_size - received))
                        if not chunk:
                            break
                        f.write(chunk)
                        received += len(chunk)
                        #logging.info(f"[{addr}] 文件: {file_path} 进度: {int((received / file_size) * 100)}%")

                # 校验文件大小
                if received != file_size:
                    logging.error(f"[{addr}] 文件接收不完整: {file_path}, 预期: {file_size}, 实际: {received}")
                    os.remove(full_path)  # 删除不完整的文件
                else:
                    logging.info(f"[{addr}] 文件接收完成: {file_path}, 大小: {received}字节")
    except Exception as e:
        logging.error(f"[{addr}] 处理错误: {e}")
    finally:
        conn.close()
        logging.info(f"[{addr}] 连接断开")

def start_server():
    global server_running
    server_running = True
    global server
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.bind(('0.0.0.0', PORT))
    server.listen(MAX_CONNECTIONS)
    server.settimeout(1.0)  # 设置超时时间为1秒
    host_ip = socket.gethostbyname(socket.gethostname())
    logging.info(f"文件传输服务器已启动，监听IP: {host_ip}, 端口: {PORT}")

    while server_running:
        try:            
            if server is None:
                logging.info("server is None")
                break
           # logging.info(f"server_running: {server_running}")
            try:
                conn, addr = server.accept()
                client_thread = threading.Thread(target=handle_client, args=(conn, addr))
                client_thread.start()
                time.sleep(0.1)  # 增加短暂的休眠时间
            except socket.timeout:
               # logging.info("超时后继续检查 server_running 状态")
                continue  # 超时后继续检查 server_running 状态
        except Exception as e:
            logging.info("服务器停止运行")
            break;


def stop_server():
    global server,server_running
    server_running = False
    if server:
        server.close()
        server = None
    logging.info("文件传输服务器已停止")